package org.lee.netty.groupchart;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * GroupChatServerHandler
 *
 * @author dralee
 * @date 2022-01-03 23:11:25
 **/
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {

    // 定义一个channel组管理所有channel
    // GlobalEventExecutor.INSTANCE是全局事件执行器，是一个单例
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private String withTime(String msg) {
        return "[".concat(sdf.format(new Date())).concat("] ").concat(msg);
    }

    // 读取数据
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 获取到当前channel
        Channel channel = ctx.channel();
        // 遍历channelGroup，根据不同情况，回送不同消息
        channelGroup.forEach(ch -> {
            if (ch != channel) { // 不是当前channel，转发消息
                ch.writeAndFlush(withTime("[客户]" + channel.remoteAddress() + " 发送消息 " + msg + "\n"));
            } else {
                ch.writeAndFlush(withTime("[自己]发送了消息 " + msg + "\n"));
            }
        });
    }

    // 表示连接建立，一旦连接，第一个被执行
    // 将当前channel加入到channelGroup
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // 将该客户加入聊天信息推送给其它在线客户端
        // 该方法会将channelGroup中所有channel遍历，并发送消息，不需要自己遍历
        channelGroup.writeAndFlush(withTime("[客户端]" + channel.remoteAddress() + " 加入聊天\n"));
        channelGroup.add(channel);
    }

    // 表示channel处于活动状态，提示xx上线
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(withTime(ctx.channel().remoteAddress() + " 上线了~"));
    }

    // 表示channel处于不活动状态，提示xx离线了
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(withTime(ctx.channel().remoteAddress() + " 离线了~"));
    }

    // 断开连接，将xx客户离开信息推送给当前在线客户
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush(withTime("[客户端]" + channel.remoteAddress() + " 离开了\n"));
        System.out.println(withTime("当前channelGroup size=" + channelGroup.size()));
    }

    // 发生异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 关闭通道
        ctx.close();
    }
}
